跳到主要内容

对象的属性劫持

本节你将学习到如何利用 JavaScript 的 Object.defineProperty 进行对象属性的劫持。

语法​

Object.defineProperty使用在一个对象上,可以新增一个属性或修改一个现有的属性。

其语法为

Object.defineProperty(obj, prop, descriptor);

参数​

参数描述
obj我们要操纵的对象
prop要操纵对象上的哪个属性值
descriptor

属性描述符,描述该属性被读取或写入时应表现的行为,分为 数据描述符 和 存取描述符 两种。

  • 数据描述符更倾向于结果
  • 存取描述符更倾向于过程。
提示

比如当我们想要读取 obj.name,如果通过数据描述符设置,应该设置这个值是什么,而存取描述符则是设置读写的时候所触发的函数。

数据描述符 和 存取描述符 都分别有各自的设置键值,但是也有共有的键值,我们先看共有的键值,有 configurable 以及 enumerable。

共有键值​

键值说明
configurable默认为 false,即除了 value 以及 writable 之外的其他属性都不能被修改。只有为 true 的时候,该属性的描述符才能被改变。
另外,writable 只能从 true 改为 false,不能从 false 改为 true。
enumerable默认为 false,只有为 true 的时候才出现在对象的枚举属性中,枚举指 Object.keys 等获取对象所有属性的 API。
注意

当对象中不存在属性的时候,会直接根据描述符默认值进行赋值,但当对象已经存在该属性,并且描述符的属性未显式声明的时候,会以已存在的属性为准,下同。

数据描述符专有属性​

数据描述符有两个属性,value 和 writable:

属性说明
value当读取该属性的时候,所返回的属性对应的值,可以是任何 JavaScript 有效的值,
如数值,对象,函数等。
writable是否可写,即 value 是否能被 赋值运算符(=) 等改变,默认为 false

存取描述符专有属性​

存取描述符有两个属性,get 和 set:

属性说明
get当访问该属性时,会调用此函数。
执行时不传入任何参数,但是会传入 this 对象
(由于继承关系,这里的 this 并不一定是定义该属性的对象)。
该函数的返回值会被用作属性的值。
set当属性值被修改时,会调用此函数。
该方法接受一个参数(也就是被赋予的新值),
会传入赋值时的 this 对象。

使用​

具体怎么用我们可以看一些小栗子,这个函数相当于在访问对象内的属性的时候进行了一层过滤,可以篡改读取到的数据以及设置的数据

可以看一下 MDN 官方的例子有一个非常好的体现

//创建一个object1
const object1 = {};
// 设置object1的属性property1,值为42,不可写
Object.defineProperty(object1, "property1", {
value: 42,
writable: false,
});
// 再设置object1的property1属性为77,但是会爆出一个错误
object1.property1 = 77; // 严格模式下会爆出错误
//访问property,结果为42
console.log(object1.property1); // 期望输出: 42

不仅仅可以设置为对象,也可以设置 set 和 get 来控制读取和写入

Object.defineProperty(obj, "attr", {
get: function () {
//获取的数据;
},
set: function (str) {
//设置的数据;
},
});